﻿
// Game.cpp : 定义应用程序的类行为。
//

#include "stdafx.h"
#include "Game.h"
#include "GameDlg.h"
#include "log.h"
#include "thread_control.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CGameApp

BEGIN_MESSAGE_MAP(CGameApp, CWinApp)
	ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CGameApp 构造

CGameApp::CGameApp()
{
	// 支持重新启动管理器
	m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

	// TODO: 在此处添加构造代码，
	// 将所有重要的初始化放置在 InitInstance 中
}


// 唯一的一个 CGameApp 对象

CGameApp theApp;

// 全局的dm对象
CDm * g_dm = NULL;


/*
* 写这个例子的原因是看到了很多用户对多线程的处理，处于一知半解的状态
* 各种奇葩写法层出不穷. 导致的问题也是稀奇古怪
* 卡死，崩溃简直是家常便饭

* 为了让用户能更深入的了解多线程的控制和处理,我要在这里写一些原理性的东西
* 包括插件的设计思想

* 首先说插件
* 插件目前是用COM架构设计的,目前的是版本同时支持sta和mta两种线程模型
* 简单来说,sta就是单线程模型,mta是多线程模型
* 对于sta来说,所有的com调用(比如你调用了插件的某个接口),都被序列化到某个线程(创建对象的那个线程)内去执行,而不一定在你的调用线程执行
* 对于mta来说,所有的com调用,都在你的调用线程执行,所以mta的调用效率是最高的.
* 那么什么时候决定com的线程模型呢? 其实是在对象创建的那个时候决定的
* 当对象创建时，所在的线程是sta模型,那么这个对象就是sta模型了，无论它在哪个线程里调用,都必定序列化
* 相反，如果创建时，所在线程是mta模型,那么这个对象就算实在sta模型的线程里调用,它也一定不会被序列化.
* 所以，我们如果想让某个COM对象以sta模型运行，那么只需要让它在sta模型的线程内创建就好了. 相反mta也如此

* 对于实际的使用中，我还是建议统统用mta模型。 因为考虑到我们会在线程外去调用接口,为了效率考虑，我们统一使用mta
* 另外插件设计的所有接口，对于同个对象而言，不是多线程安全的.(也就是同个对象的接口，不能同时在多个线程内调用,会引发崩溃)
* 在实际使用中，一定要时刻注意这一点. 相反的，如果不是同个对象，那么是多线程安全的.

* 然后我们说一下系统的多线程
* 系统的多线程其实就是创建，暂停，恢复，强制结束这4个接口
* 先告诉大家结论，暂停这个接口,永远不要去调用. 强制结束这个接口要尽可能避免调用.
* 很多用户为了方便，在暂停某个脚本时，使用了系统提供的暂停接口
* 结果导致了各种卡死，崩溃。 还不知道咋回事。 感觉明明代码写的没毛病啊
* 这里我要说一下，系统提供的暂停(SuspendThread)操作,压根就不是给正常用户使用的,这是给调试器使用的
* 那为何这个暂停操作会导致异常呢？ 实际上,线程在运行当中，它的状态是不可控的
* 假如你要暂停的线程正好处于某个锁当中(E语言也叫做许可证),万一恰巧这个锁还是个全局的，你说会发生什么事情？
* 而恰巧的是，系统中使用全局锁的操作很频繁. 比如分配内存/释放内存.
* 所以我给大家的建议是，永远不要去用暂停这个接口.
* 至于强制结束线程，也是非常不建议使用，它和暂停线程有相同的作用. 假如结束的线程正好处于锁当中,BOOM!!!
* 那么今天的例子也就是给大家演示，如何不用这几个要命的接口，如何正确的使用多线程.
* 至于上面说的暂停，恢复我们有别的方法替代完成.
* 相信如果你真的理解了这个例子，那么你操作多线程真的会做到游刃有余!
*/

// CGameApp 初始化

BOOL CGameApp::InitInstance()
{
	CoInitializeEx(NULL, 0);
	// 如果一个运行在 Windows XP 上的应用程序清单指定要
	// 使用 ComCtl32.dll 版本 6 或更高版本来启用可视化方式，
	//则需要 InitCommonControlsEx()。  否则，将无法创建窗口。
	INITCOMMONCONTROLSEX InitCtrls;
	InitCtrls.dwSize = sizeof(InitCtrls);
	// 将它设置为包括所有要在应用程序中使用的
	// 公共控件类。
	InitCtrls.dwICC = ICC_WIN95_CLASSES;
	InitCommonControlsEx(&InitCtrls);

	CWinApp::InitInstance();


	AfxEnableControlContainer();

	// 创建 shell 管理器，以防对话框包含
	// 任何 shell 树视图控件或 shell 列表视图控件。
	CShellManager *pShellManager = new CShellManager;

	// 激活“Windows Native”视觉管理器，以便在 MFC 控件中启用主题
	CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

	// 标准初始化
	// 如果未使用这些功能并希望减小
	// 最终可执行文件的大小，则应移除下列
	// 不需要的特定初始化例程
	// 更改用于存储设置的注册表项
	// TODO: 应适当修改该字符串，
	// 例如修改为公司或组织名
	SetRegistryKey(_T("应用程序向导生成的本地应用程序"));
	// 初始化
	LogInit();
	ThreadInit();

	HMODULE hLib = LoadLibrary(L"dm.dll");
	if (hLib < (HMODULE)HINSTANCE_ERROR)
	{
		AfxMessageBox(L"加载大漠dll失败,或者尝试手动注册大漠!");
		return FALSE;

	}
	TRACE(L"[sdn] Reg 11111");
	FARPROC lpDllEntryPoint = GetProcAddress(hLib, "DllRegisterServer");
	if (lpDllEntryPoint == NULL)
	{
		AfxMessageBox(L"找不到注册入口,或者尝试手动注册大漠!");
		return FALSE;
	}

	if (FAILED((*lpDllEntryPoint)()))
	{
		AfxMessageBox(L"注册大漠插件失败！尝试手动注册！参见帮助文档!");
		return FALSE;
	}

	FreeLibrary(hLib);

	// 创建对象,此对象必须全局保持
	g_dm = new CDm;
	if (g_dm == NULL)
	{
		Log(_T("对象创建失败"));
		return 0;
	}
	CString result=L"dm00000012948d1529c48ec8017d9f6a2e033ddb3";
	//result.LoadString(IDS_STRING_DM);
	// 收费注册
	long dm_ret = g_dm->Reg(result,_T(""));
	if (dm_ret != 1)
	{
		Log(_T("收费注册失败,返回值:%d"),dm_ret);
		delete g_dm;
		return 0;
	}
	CString str;
	
	Log(g_dm->Ver());

	// 这里可以做一些初始化设定
	// 比如开启保护盾,设置全局字库等
#if 0
	dm_ret = g_dm->DmGuard(1, _T("memory"));
	if (dm_ret != 1)
	{
		Log(_T("开启保护盾失败:%d"), dm_ret);
		delete g_dm;
		return 0;
	}
#endif


	// 这里我们设置一下全局字库
	g_dm->SetPath(_T("c:\\MobileGame\\pic\\"));
	g_dm->EnableShareDict(1);
	g_dm->SetShowErrorMsg(0);
	//g_dm->SetDict(0,_T("1.txt"));
	//g_dm->WriteIniPwd(L"Global", L"var1", L"123", L"d:\\cfg.ini", L"1234");

	CGameDlg dlg;
	m_pMainWnd = &dlg;
	INT_PTR nResponse = dlg.DoModal();
	if (nResponse == IDOK)
	{
		// TODO: 在此放置处理何时用
		//  “确定”来关闭对话框的代码
	}
	else if (nResponse == IDCANCEL)
	{
		// TODO: 在此放置处理何时用
		//  “取消”来关闭对话框的代码
	}
	else if (nResponse == -1)
	{
		TRACE(traceAppMsg, 0, "警告: 对话框创建失败，应用程序将意外终止。\n");
		TRACE(traceAppMsg, 0, "警告: 如果您在对话框上使用 MFC 控件，则无法 #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS。\n");
	}

	// 删除上面创建的 shell 管理器。
	if (pShellManager != NULL)
	{
		delete pShellManager;
	}

#ifndef _AFXDLL
	ControlBarCleanUp();
#endif

	// 由于对话框已关闭，所以将返回 FALSE 以便退出应用程序，
	//  而不是启动应用程序的消息泵。
	return FALSE;
}

